package com.vvv.designpattern.items.vistor;

import com.vvv.designpattern.items.composite.AbstractProductItem;
import com.vvv.designpattern.items.composite.ProductComposite;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

import static com.vvv.designpattern.constants.RedisConstants.CACHE_PRODUCT_COMPOSITE_KEY;

/**
 * @author vvv
 * @date 2023-11-19 14 34
 * discription
 */
@Component
public class AddItemVisitor implements ItemVisitor<AbstractProductItem> {
    /**
     * ObjectStructure 数据提供者，在这里redis就是数据提供者
     */
    @Resource
    private RedisTemplate redisTemplate;

    @Override
    public AbstractProductItem visitor(AbstractProductItem productItem) {
        // 1. 从redis中获取商品类目信息（树形结构）
        ProductComposite currentItem = (ProductComposite) redisTemplate.opsForValue().get(CACHE_PRODUCT_COMPOSITE_KEY);
        if (currentItem == null) {
            throw new UnsupportedOperationException("Product items should not be empty in redis!");
        }
        // 2. 添加节点
        ProductComposite addItem = (ProductComposite) productItem;
        // 如果添加节点是pid是当前节点直接设置并返回
        if (addItem.getPid().equals(currentItem.getId())) {
            currentItem.addProductItem(addItem);
            return currentItem;
        }
        // 递归处理
        if (!addChild(addItem, currentItem)) {
            throw new UnsupportedOperationException("addItem's pid is error! ");
        }
        // 3. 返回
        return currentItem;
    }

    private boolean addChild(ProductComposite addItem, ProductComposite currentItem) {
        for (AbstractProductItem abstractItem : currentItem.getChild()) {
            ProductComposite item = (ProductComposite) abstractItem;
            if (item.getId().equals(addItem.getPid())) {
                item.addProductItem(currentItem);
                return true;
            } else {
                if (addChild(addItem, item)) {
                    return true;
                }
            }
        }
        return false;
    }
}
